package oss

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/vueadmin/utils"
	"mime/multipart"
	"strings"
	"time"
)

type AliyunOss struct {
	Endpoint        string
	AccessKeyId     string
	AccessKeySecret string
	BucketName      string
	Callback        string
}

func NewAliyunOss(config string) *AliyunOss {
	var aliyunoss AliyunOss
	json.Unmarshal([]byte(config), &aliyunoss)
	return &aliyunoss
}

// 上传
func (p AliyunOss) Upload(file *multipart.FileHeader, key string) string {
	isCname := strings.Contains(p.Endpoint, "aliyuncs.com")
	bucket, err := p.NewBucket(isCname)
	if err != nil {
		panic(err)
	}

	f, openError := file.Open()
	if openError != nil {
		panic(openError)
	}
	defer f.Close()

	err = bucket.PutObject(strings.TrimLeft(key, "/"), f)
	if err != nil {
		panic(err)
	}
	var fileName string
	if isCname {
		fileName = utils.GetEndPoint(p.Endpoint, p.BucketName) + key
	} else {
		fileName = p.Endpoint + key
	}
	return fileName
}

func (p AliyunOss) NewBucket(isCname bool) (*oss.Bucket, error) {
	client, err := oss.New(p.Endpoint, p.AccessKeyId, p.AccessKeySecret, oss.UseCname(!isCname))
	if err != nil {
		return nil, err
	}
	bucket, err := client.Bucket(p.BucketName)
	if err != nil {
		return nil, err
	}
	return bucket, nil
}

// 删除图片
func (p AliyunOss) DeleteFile(key string) bool {
	bucket, err := p.NewBucket(false)
	if err != nil {
		panic(err)
	}
	err = bucket.DeleteObject(key)
	if err != nil {
		panic(err)
	}
	return true
}

// 获取客户端上传配置信息
func (p AliyunOss) GetCliendConfig(key string) map[string]interface{} {
	options := make(map[string]interface{})
	expire := 30 // 设置该policy超时时间是30s。即这个policy过了这个有效时间，将不能访问。
	now := time.Now()
	end := now.Add(time.Second * time.Duration(expire))
	options["expiration"] = end.UTC().Format("2006-01-02T15:04:05Z") // 授权过期时间

	conditions := make([]interface{}, 0)
	conditions = append(conditions, map[string]interface{}{"bucket": p.BucketName})

	callbackParam := map[string]interface{}{
		"callbackUrl":      p.Callback,
		"callbackBody":     "${object}",
		"callbackBodyType": "application/x-www-form-urlencoded",
	}
	callbackString, _ := json.Marshal(callbackParam)
	base64CallbackBody := base64.StdEncoding.EncodeToString(callbackString)

	contentLengthRange := make([]interface{}, 0)
	contentLengthRange = append(contentLengthRange, "content-length-range")
	contentLengthRange = append(contentLengthRange, 0)
	contentLengthRange = append(contentLengthRange, 2048*1024*1024)
	conditions = append(conditions, contentLengthRange)

	options["conditions"] = conditions
	policyBytes, _ := json.Marshal(options)
	policy := base64.StdEncoding.EncodeToString(policyBytes)

	mac := hmac.New(sha1.New, []byte(p.AccessKeySecret))
	mac.Write([]byte(policy))
	sign := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	data := map[string]interface{}{
		"sign":           sign,
		"policy":         policy,
		"callback":       base64CallbackBody,
		"OSSAccessKeyId": p.AccessKeyId,
		"serverurl":      utils.GetEndPoint(p.Endpoint, p.BucketName),
		"key":            key,
		"type":           "ali",
	}
	return data
}
